"""
图书库管理系统表格视图
基于data.csv的图书数据展示和编辑
使用PySide6实现
"""

from nt import read
import sys
import csv
import time
from typing import Dict
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QScrollBar, QTableView, QTreeView, QVBoxLayout, QWidget,
    QPushButton, QFileDialog, QHeaderView, QStyledItemDelegate,
    QComboBox, QHBoxLayout, QLabel, QLineEdit, QMessageBox,
    QDockWidget, QTextEdit, QDateEdit, QStyleOptionComboBox, QStyle, QCheckBox,QDateEdit,
    QColorDialog
)
from PySide6.QtCore import Qt, QAbstractTableModel, QAbstractItemModel, QModelIndex, QTimer, QDate, QEvent,QRect
from PySide6.QtGui import QColor, QStandardItemModel, QStandardItem,QDoubleValidator



class RBookComboBoxDelegate(QStyledItemDelegate):
    """图书分类/作者/状态的下拉框代理"""
    
    def __init__(self, options, parent=None):
        super().__init__(parent)
        self.options = options  # 下拉选项列表
        self._editor_count = 0
        self._last_click_pos = None  # 记录最后一次点击位置
    
    def editorEvent(self, event, model, option, index):
        """单击触发编辑，并记录点击位置"""
        if event.type() == QEvent.Type.MouseButtonRelease:
            if event.button() == Qt.MouseButton.LeftButton:
                # 记录点击位置（相对于单元格）
                self._last_click_pos = event.pos()
                view = option.widget
                if view:
                    view.edit(index)
                return True
        return super().editorEvent(event, model, option, index)
    
    def createEditor(self, parent, option, index):
        """创建下拉框编辑器，如果点击三角区域则立即展开"""
        self._editor_count += 1
        editor_id = self._editor_count
        
        print(f"[BookDelegate] 创建编辑器 #{editor_id} - {self.options[:3]}...")
        
        editor = QComboBox(parent)
        editor.setEditable(False)
        editor.setProperty("_model_index",index)
        
        # 添加选项
        for opt in self.options:
            editor.addItem(opt)
        
        # 连接activated信号：选择项后立即提交并关闭编辑器
        editor.activated.connect(lambda: self._commit_and_close(editor))
        
        # 自定义showPopup：滚动到顶部 + 显示在正下方
        original_show_popup = editor.showPopup
        def custom_show_popup():
            original_show_popup()
            
            list_view = editor.view()
            if list_view:
                list_view.scrollToTop()
                
                popup = list_view.parent()
                if popup:
                    combo_pos = editor.mapToGlobal(editor.rect().bottomLeft())
                    popup.move(combo_pos)
        
        editor.showPopup = custom_show_popup
        editor.destroyed.connect(lambda: print(f"[BookDelegate] 编辑器 #{editor_id} 已销毁"))
        
        # 判断是否点击了三角区域，如果是则立即展开下拉列表
        if 0:#self._last_click_pos:
            arrow_width = 20
            arrow_rect = option.rect.adjusted(option.rect.width() - arrow_width, 0, -2, 0)
            if arrow_rect.contains(self._last_click_pos):
                # 使用QTimer延迟调用，确保编辑器完全初始化
                from PySide6.QtCore import QTimer
                QTimer.singleShot(0, editor.showPopup)
            # 清除点击位置
            self._last_click_pos = None
        
        from PySide6.QtCore import QTimer
        QTimer.singleShot(0, editor.showPopup)
        
        return editor
    
    def _commit_and_close(self, editor):
        """提交数据并关闭编辑器"""
        self.commitData.emit(editor)
        self.closeEditor.emit(editor, QStyledItemDelegate.EndEditHint.NoHint)

    def paint(self, painter, option, index):   
        """自定义绘制ComboBox样式：边框 + 文本 + 下拉三角形"""
        painter.save()
        
        # 1. 绘制背景（使用模型返回的背景色）
        if option.state & QStyle.StateFlag.State_Selected:
            painter.fillRect(option.rect, option.palette.highlight())
        else:
            # 从模型获取背景色
            bg_color = index.data(Qt.ItemDataRole.BackgroundRole)
            if bg_color:
                painter.fillRect(option.rect, bg_color)
            else:
                painter.fillRect(option.rect, option.palette.base())
        
        # 2. 绘制边框
        from PySide6.QtGui import QPen
        pen = QPen(QColor(180, 180, 180), 1)  # 灰色边框
        painter.setPen(pen)
        # 留出1像素边距，避免边框被截断
        border_rect = option.rect.adjusted(1, 1, -1, -1)
        painter.drawRect(border_rect)
        
        # 3. 计算区域
        arrow_width = 20  # 下拉箭头区域宽度
        text_rect = option.rect.adjusted(5, 0, -arrow_width - 5, 0)  # 文本区，左边距5px
        arrow_rect = option.rect.adjusted(option.rect.width() - arrow_width, 0, -2, 0)  # 箭头区
        
        # 4. 绘制文本
        text = index.data(Qt.ItemDataRole.DisplayRole) or index.data(Qt.ItemDataRole.EditRole) or ''
        if option.state & QStyle.StateFlag.State_Selected:
            painter.setPen(option.palette.highlightedText().color())
        else:
            painter.setPen(option.palette.text().color())
        painter.drawText(text_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, text)
        
        # 5. 绘制下拉三角形
        from PySide6.QtGui import QPolygon
        from PySide6.QtCore import QPoint
        
        # 三角形中心点
        center_x = arrow_rect.center().x()
        center_y = arrow_rect.center().y()
        
        # 三角形顶点（向下的三角形）
        triangle = QPolygon([
            QPoint(center_x - 4, center_y - 2),  # 左上
            QPoint(center_x + 4, center_y - 2),  # 右上
            QPoint(center_x, center_y + 3)       # 底部中心
        ])
        
        painter.setPen(Qt.PenStyle.NoPen)
        painter.setBrush(QColor(100, 100, 100))  # 深灰色三角形
        painter.drawPolygon(triangle)
        
        painter.restore()
    
    def setEditorData(self, editor, index):
        """设置编辑器当前值"""
        value = index.model().data(index, Qt.ItemDataRole.EditRole)
        if value and value in self.options:
            idx = self.options.index(value)
            editor.setCurrentIndex(idx)
        else:
            editor.setCurrentIndex(0)
    
    def setModelData(self, editor, model, index):
        """保存编辑器的值"""
        print("setModelData+++++++++++++++")
        value = editor.currentText()
        model.setData(index, value, Qt.ItemDataRole.EditRole)
    
    def updateEditorGeometry(self, editor, option, index):
        """更新编辑器位置"""
        editor.setGeometry(option.rect)


class RBookCheckBoxDelegate(QStyledItemDelegate):
    """CheckBox代理 - 用于borrowed列等布尔值或数字切换"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
    
    def paint(self, painter, option, index):
        """绘制CheckBox + 数值文本"""
        # 获取数据值
        value = index.data(Qt.ItemDataRole.DisplayRole)
        
        # 判断是否选中（borrowed > 0 为选中）
        try:
            num_value = int(value) if value else 0
            checked = num_value > 0
        except (ValueError, TypeError):
            num_value = 0
            checked = False
        
        # 绘制背景（使用模型返回的背景色）
        painter.save()
        if option.state & QStyle.StateFlag.State_Selected:
            painter.fillRect(option.rect, option.palette.highlight())
        else:
            # 从模型获取背景色
            bg_color = index.data(Qt.ItemDataRole.BackgroundRole)
            if bg_color:
                painter.fillRect(option.rect, bg_color)
            else:
                painter.fillRect(option.rect, option.palette.base())
        
        # 使用系统样式绘制CheckBox
        from PySide6.QtWidgets import QStyleOptionButton
        checkbox_option = QStyleOptionButton()
        
        # 计算CheckBox位置（左侧）
        checkbox_size = 18
        checkbox_x = option.rect.x() + 5  # 左边距5px
        checkbox_y = option.rect.y() + (option.rect.height() - checkbox_size) // 2
        checkbox_option.rect = QRect(checkbox_x, checkbox_y, checkbox_size, checkbox_size)
        
        # 设置状态
        checkbox_option.state = QStyle.StateFlag.State_Enabled
        if checked:
            checkbox_option.state |= QStyle.StateFlag.State_On
        else:
            checkbox_option.state |= QStyle.StateFlag.State_Off
        
        # 绘制CheckBox
        QApplication.style().drawControl(QStyle.ControlElement.CE_CheckBox, checkbox_option, painter)
        
        # 绘制数值文本（CheckBox右侧）
        text_rect = option.rect.adjusted(checkbox_size + 10, 0, -5, 0)  # CheckBox后面留10px间距
        if option.state & QStyle.StateFlag.State_Selected:
            painter.setPen(option.palette.highlightedText().color())
        else:
            painter.setPen(option.palette.text().color())
        if num_value > 0 :
            painter.drawText(text_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, str("借出"))
        else:
            painter.drawText(text_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, str("未借出"))
        
        painter.restore()
    
    def editorEvent(self, event, model, option, index):
        """处理点击事件切换CheckBox状态"""
        if event.type() == QEvent.Type.MouseButtonRelease:
            if event.button() == Qt.MouseButton.LeftButton:
                # 获取当前值
                current_value = index.data(Qt.ItemDataRole.EditRole)
                try:
                    current_num = int(current_value) if current_value else 0
                except (ValueError, TypeError):
                    current_num = 0
                
                # 点击切换：如果是0则变为1，如果>0则变为0
                if current_num == 0:
                    new_value = 1  
                else:
                    new_value = 0  
                
                # 保存到模型
                model.setData(index, str(new_value), Qt.ItemDataRole.EditRole)
                return True
        
        return super().editorEvent(event, model, option, index)

class RBookDateDelegate(QStyledItemDelegate):
    """日期列的代理"""
    _editor_count = 0  # 统计编辑器创建次数
    def createEditor(self, parent, option, index):
        """创建日期编辑器"""
        editor = QDateEdit(parent)
        RBookDateDelegate._editor_count += 1
        editor_id = RBookDateDelegate._editor_count
        print(f"[Delegate] 创建编辑器 #{editor_id} - parent: {parent.__class__.__name__}")
        editor.setCalendarPopup(True) 
        editor.setDisplayFormat('yyyy-MM-dd')  
        editor.destroyed.connect(lambda: print(f"[Delegate] 编辑器 #{editor_id} 已销毁"))
        return editor
    
    def setEditorData(self, editor, index):
        """设置编辑器的当前值"""
        value = index.model().data(index, Qt.EditRole)
        if value:
            try:
                date = QDate.fromString(str(value), 'yyyy-MM-dd')
                if date.isValid():
                    editor.setDate(date)
                else:
                    editor.setDate(QDate.currentDate())
            except:
                editor.setDate(QDate.currentDate())
        else:
            editor.setDate(QDate.currentDate())
    
    def setModelData(self, editor, model, index):
        """将编辑器的值保存到模型"""
        date = editor.date()
        value = date.toString('yyyy-MM-dd')
        model.setData(index, value, Qt.EditRole)


class RBookLineEditDelegate(QStyledItemDelegate):
    """数字范围LineEdit代理（用于price和discount）"""
    _editor_count = 0  # 统计编辑器创建次数
    def __init__(self, min_value=0.0, max_value=1.0, decimals=2, parent=None):
        super().__init__(parent)
        self.min_value = min_value
        self.max_value = max_value
        self.decimals = decimals
    
    def createEditor(self, parent, option, index):
        """创建数字输入编辑器"""
        editor: QLineEdit = QLineEdit(parent)
        RBookLineEditDelegate._editor_count += 1
        editor_id = RBookLineEditDelegate._editor_count
        print(f"[Delegate] 创建编辑器 #{editor_id} - parent: {parent.__class__.__name__}")
        # 设置数字验证器
        # validator = QDoubleValidator(self.min_value, self.max_value, self.decimals, editor)
        # validator.setNotation(QDoubleValidator.StandardNotation)
        # editor.setValidator(validator)
        editor.destroyed.connect(lambda: print(f"[Delegate] 编辑器 #{editor_id} 已销毁"))
        return editor
    
    def setEditorData(self, editor, index):
        """设置编辑器的当前值"""
        value = index.model().data(index, Qt.EditRole)
        if value:
            editor.setText(str(value))
        else:
            editor.setText('0.0')
    
    def setModelData(self, editor, model, index):
        """将编辑器的值保存到模型"""
        text = editor.text()
        try:
            #value = float(text) if text else 0.0
            # 确保值在范围内
            #value = max(self.min_value, min(self.max_value, value))
            model.setData(index, text, Qt.EditRole)
        except ValueError:
            # 如果转换失败，保持原值
            pass

class RBookColorDelegate(QStyledItemDelegate):
    """颜色块代理 - 显示和选择颜色"""
    _editor_count = 0
    
    def __init__(self, parent=None):
        super().__init__(parent)
    
    def paint(self, painter, option, index):
        """绘制颜色块"""
        painter.save()
        
        # 获取颜色值（支持多种格式）
        value = index.data(Qt.ItemDataRole.DisplayRole)
        color = self._parse_color(value)
        
        # 绘制选中背景
        if option.state & QStyle.StateFlag.State_Selected:
            painter.fillRect(option.rect, option.palette.highlight())
        else:
            # 从模型获取背景色
            bg_color = index.data(Qt.ItemDataRole.BackgroundRole)
            if bg_color:
                painter.fillRect(option.rect, bg_color)
            else:
                painter.fillRect(option.rect, option.palette.base())
        
        # 计算颜色块区域（左侧）
        color_block_size = min(option.rect.height() - 6, 30)  # 颜色块大小
        color_block_x = option.rect.x() + 5
        color_block_y = option.rect.y() + (option.rect.height() - color_block_size) // 2
        color_block_rect = QRect(color_block_x, color_block_y, color_block_size, color_block_size)
        
        # 绘制颜色块
        painter.fillRect(color_block_rect, color)
        
        # 绘制颜色块边框
        from PySide6.QtGui import QPen
        pen = QPen(QColor(120, 120, 120), 1)
        painter.setPen(pen)
        painter.drawRect(color_block_rect)
        
        # 绘制颜色值文本（颜色块右侧）
        text_rect = option.rect.adjusted(color_block_size + 10, 0, -5, 0)
        if option.state & QStyle.StateFlag.State_Selected:
            painter.setPen(option.palette.highlightedText().color())
        else:
            painter.setPen(option.palette.text().color())
        
        # 显示颜色值（RGB或十六进制）
        if value:
            display_text = str(value)
        else:
            display_text = color.name()  # 显示十六进制值
        
        painter.drawText(text_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, display_text)
        
        painter.restore()
    
    def _parse_color(self, value):
        """解析颜色值，支持多种格式"""
        if not value:
            return QColor(255, 255, 255)  # 默认白色
        
        value_str = str(value).strip()
        
        # 尝试解析 #RRGGBB 格式
        if value_str.startswith('#'):
            color = QColor(value_str)
            if color.isValid():
                return color
        
        # 尝试解析 R,G,B 格式
        if ',' in value_str:
            try:
                parts = [int(p.strip()) for p in value_str.split(',')]
                if len(parts) == 3:
                    return QColor(parts[0], parts[1], parts[2])
            except ValueError:
                pass
        
        # 尝试解析颜色名称
        color = QColor(value_str)
        if color.isValid():
            return color
        
        return QColor(255, 255, 255)  # 默认白色
    
    def editorEvent(self, event, model, option, index):
        """处理点击事件，打开颜色选择器"""
        if event.type() == QEvent.Type.MouseButtonRelease:
            if event.button() == Qt.MouseButton.LeftButton:
                # 获取当前颜色
                value = index.data(Qt.ItemDataRole.EditRole)
                current_color = self._parse_color(value)
                
                # 打开颜色选择对话框
                color = QColorDialog.getColor(current_color, option.widget, "选择颜色")
                
                if color.isValid():
                    # 保存为 #RRGGBB 格式
                    color_value = color.name()
                    model.setData(index, color_value, Qt.ItemDataRole.EditRole)
                
                return True
        
        return super().editorEvent(event, model, option, index)

class RBookTreeModel(QStandardItemModel):
    """图书树形模型 - 支持分类→作者→书名三级折叠"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self._raw_data = []  # 原始数据
        self._headers = []
        self._total_count = 0  # CSV文件总行数
        self._loaded_count = 0  # 已加载行数
        self._category_nodes = {}  # 缓存分类节点
        self._author_nodes = {}    # 缓存作者节点
        
    def load_csv_to_tree(self, filepath, max_rows=None):
        """加载CSV文件并构建树形结构"""
        start_time = time.time()
        
        try:
            # 读取CSV数据
            with open(filepath, 'r', encoding='utf-8') as f:
                reader = csv.reader(f)
                total_line = next(reader)  # 第一行是总行数
                self._total_count = int(total_line[0])
                self._headers = next(reader)  # 第二行是表头
                
                # 读取数据
                if max_rows == -1:
                    self._raw_data = [row for row in reader]
                elif max_rows:
                    self._raw_data = []
                    for i, row in enumerate(reader):
                        if i >= max_rows:
                            break
                        self._raw_data.append(row)
                else:
                    self._raw_data = [row for row in reader]
            
            self._loaded_count = len(self._raw_data)
            
            # 设置表头
            self.setHorizontalHeaderLabels(self._headers)
            
            # 构建树形结构
            self._build_tree_structure()
            
            elapsed_time = time.time() - start_time
            load_type = f"分批加载({max_rows}行)" if max_rows else "全量加载"
            message = f"成功加载 {len(self._raw_data)} 行数据 | {load_type} | 耗时: {elapsed_time:.3f}秒"
            
            print(f"[TreePerformance] {message}")
            return True, message
        except Exception as e:
            elapsed_time = time.time() - start_time
            return False, f"加载失败: {str(e)} | 耗时: {elapsed_time:.3f}秒"
    
    def _build_tree_structure(self):
        """构建树形结构：分类→作者→书名"""
        self.clear()
        self.setHorizontalHeaderLabels(self._headers)
        
        # 重置节点缓存
        self._category_nodes = {}
        self._author_nodes = {}
        
        # 获取category, author, title的列索引
        category_idx = self._headers.index('category') if 'category' in self._headers else 0
        author_idx = self._headers.index('author') if 'author' in self._headers else 1
        title_idx = self._headers.index('title') if 'title' in self._headers else 2
        
        # 按分类、作者、书名排序
        sorted_data = sorted(self._raw_data, key=lambda x: (x[category_idx], x[author_idx], x[title_idx]))
        
        for row_data in sorted_data:
            self._add_book_to_tree(row_data, category_idx, author_idx, title_idx)
        
        print(f"[树结构] 分类: {len(self._category_nodes)}, 作者: {len(self._author_nodes)}, 图书: {len(sorted_data)}")
    
    def _add_book_to_tree(self, row_data, category_idx, author_idx, title_idx):
        """将单本书添加到树形结构（支持增量添加）"""
        category = row_data[category_idx]
        author = row_data[author_idx]
        title = row_data[title_idx]
        
        # 1. 创建或获取分类节点
        if category not in self._category_nodes:
            category_item = QStandardItem(f"📚 {category}")
            category_item.setEditable(False)
            self._category_nodes[category] = category_item
            self.appendRow(category_item)
        
        category_node = self._category_nodes[category]
        
        # 2. 创建或获取作者节点
        author_key = (category, author)
        if author_key not in self._author_nodes:
            author_item = QStandardItem(f"✍️ {author}")
            author_item.setEditable(False)
            self._author_nodes[author_key] = author_item
            category_node.appendRow(author_item)
        
        author_node = self._author_nodes[author_key]
        
        # 3. 创建书籍节点（完整数据行）
        book_items = []
        for col_idx, cell_value in enumerate(row_data):
            item = QStandardItem(str(cell_value))
            
            # 设置可编辑列
            editable_columns = ['category', 'author', 'title', 'publisher', 'status', 'notes']
            col_name = self._headers[col_idx] if col_idx < len(self._headers) else ''
            if col_name in editable_columns:
                item.setEditable(True)
            else:
                item.setEditable(False)
            
            # 设置背景色
            if col_name == 'status':
                if cell_value == '借出':
                    item.setBackground(QColor(255, 230, 230))
                elif cell_value == '在架':
                    item.setBackground(QColor(230, 255, 230))
                elif cell_value == '维修':
                    item.setBackground(QColor(255, 245, 200))
                elif cell_value == '下架':
                    item.setBackground(QColor(220, 220, 220))
            
            book_items.append(item)
        
        author_node.appendRow(book_items)
    
    def append_more_data(self, filepath, batch_size=1000):
        """追加加载更多数据（懒加载）"""
        if self._loaded_count >= self._total_count - 2:
            return 0, "所有数据已加载完成"
        
        start_time = time.time()
        
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                reader = csv.reader(f)
                next(reader)  # 跳过总行数
                next(reader)  # 跳过表头
                
                # 跳过已加载的数据
                for _ in range(self._loaded_count):
                    next(reader)
                
                # 获取列索引
                category_idx = self._headers.index('category') if 'category' in self._headers else 0
                author_idx = self._headers.index('author') if 'author' in self._headers else 1
                title_idx = self._headers.index('title') if 'title' in self._headers else 2
                
                # 读取新批次数据
                new_rows = []
                for i, row in enumerate(reader):
                    if i >= batch_size:
                        break
                    new_rows.append(row)
                    self._raw_data.append(row)
                
                # 按分类、作者排序后增量添加到树中
                sorted_new_rows = sorted(new_rows, key=lambda x: (x[category_idx], x[author_idx], x[title_idx]))
                
                for row_data in sorted_new_rows:
                    self._add_book_to_tree(row_data, category_idx, author_idx, title_idx)
                
                self._loaded_count += len(new_rows)
                
                elapsed_time = time.time() - start_time
                message = f"追加加载 {len(new_rows)} 行 | 总计: {self._loaded_count}/{self._total_count-2} | 耗时: {elapsed_time:.3f}秒"
                print(f"[TreePerformance] {message}")
                
                return len(new_rows), message
        except Exception as e:
            return 0, f"追加加载失败: {str(e)}"
    
    def get_headers(self):
        """获取表头"""
        return self._headers
    
    def get_raw_data(self):
        """获取原始数据"""
        return self._raw_data
    
    def get_load_progress(self):
        """获取加载进度"""
        total = self._total_count - 2 if self._total_count > 2 else 0
        return {
            'loaded': self._loaded_count,
            'total': total,
            'remaining': max(0, total - self._loaded_count)
        }


class RBookTableModel(QAbstractTableModel):
    """图书数据模型 - 支持大数据量和树形排序"""
    
    def __init__(self, data=None, headers=None, parent=None):
        super().__init__(parent)
        self._total_count : int = 0
        self._data = data or []
        self._headers = headers or []
        self._headers_col = Dict[str,int]
        self._filtered_indices = None
        self._use_filter = False
        self._render_count = 0
        self._rendered_rows = set()
    
    def _get_header(self, col):
        return self._headers[col] if col < len(self._headers) else ''
    
    def rowCount(self, parent=QModelIndex()):
        if self._use_filter and self._filtered_indices is not None:
            return len(self._filtered_indices)
        return len(self._data)
    
    def columnCount(self, parent=QModelIndex()):
        return len(self._headers) if self._headers else 0
    
    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if not index.isValid():
            return None
        
        row = index.row()
        col = index.column()
        
        actual_row = self._get_actual_row(row)
        if actual_row >= len(self._data):
            return None
        
        # 渲染统计
        if col == 0:
            self._rendered_rows.add(actual_row)
            self._render_count += 1
        
        if role == Qt.ItemDataRole.DisplayRole or role == Qt.ItemDataRole.EditRole:
            return self._data[actual_row][col]
        
        if role == Qt.ItemDataRole.BackgroundRole: 
            colors = self._data[actual_row][self._headers_col['color']]
            #return QColor(colors)
            notes = self._data[actual_row][self._headers_col['notes']]
            colors = {
                ''    : QColor(255, 255, 255), 
                '热门': QColor(255, 10, 20), 
                '新书': QColor(240, 125, 20), 
                '推荐': QColor(240, 255, 20), 
                '畅销': QColor(255, 250, 120),  
                '经典': QColor(245, 245, 180),  
                '珍藏版': QColor(255, 150, 230)  
            }
            return colors.get(notes, QColor(255, 255, 255))
        
        
        return None
    
    def _get_actual_row(self, display_row):
        """获取实际行索引"""
        if self._use_filter and self._filtered_indices is not None:
            if display_row < len(self._filtered_indices):
                return self._filtered_indices[display_row]
            return len(self._data)
        return display_row
    
    def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
        """设置数据"""
        if role == Qt.ItemDataRole.EditRole:
            row = index.row()
            col = index.column()
            actual_row = self._get_actual_row(row)
            if actual_row < len(self._data):
                self._data[actual_row][col] = value
                print("setData============")
                self.dataChanged.emit(index, index, [Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole])
                return True
        return False
    
    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                return self._headers[section] if section < len(self._headers) else ''
            else:
                return str(section + 1)
        return None
    
    def flags(self, index):
        """设置可编辑列"""
        if not index.isValid():
            return Qt.ItemFlag.ItemIsEnabled
        
        col = index.column()
        col_name = self._headers[col] if col < len(self._headers) else ''
        
        # 可编辑列：category, author, title, publisher, status, notes, borrowed, publish_date
        editable_columns = ['category', 'author', 'title', 'publisher', 'status', 'notes', 'borrowed', 'publish_date']
        #editable_columns = []
        if col_name in editable_columns:
            return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable
        
        return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable
    
    def load_csv(self, filepath, load_rows=None):
        """加载CSV文件"""
        start_time = time.time()
        
        try:
            self.beginResetModel()
            with open(filepath, 'r', encoding='utf-8') as f:
                reader = csv.reader(f)
                
                # 第一行是总行数
                total_line = next(reader)
                self._total_count = int(total_line[0])
                print(f"文件声明总行数: {total_line[0]}")
                
                # 第二行是表头
                self._headers = next(reader)
                self._headers_col = {h: i for i, h in enumerate(self._headers)}
                # 读取数据
                if load_rows:
                    self._data = []
                    for i, row in enumerate(reader):
                        if i >= load_rows:
                            break
                        self._data.append(row)
                else:
                    self._data = [row for row in reader]
            
            self._use_filter = False
            self._filtered_indices = None
            self.endResetModel()
            
            elapsed_time = time.time() - start_time
            load_type = f"分批加载({load_rows}行)" if load_rows else "全量加载"
            message = f"成功加载 {len(self._data)} 行数据 | {load_type} | 耗时: {elapsed_time:.3f}秒"
            
            print(f"[Performance] {message}")
            return True, message
        except Exception as e:
            elapsed_time = time.time() - start_time
            self.endResetModel()
            return False, f"加载失败: {str(e)} | 耗时: {elapsed_time:.3f}秒"
    
    def filter_data(self, search_text):
        """搜索过滤"""
        if not search_text:
            self._use_filter = False
            self._filtered_indices = None
            self.layoutChanged.emit()
            return
        
        search_lower = search_text.lower()
        self._filtered_indices = []
        
        for i, row in enumerate(self._data):
            for cell in row:
                if search_lower in str(cell).lower():
                    self._filtered_indices.append(i)
                    break
        
        self._use_filter = True
        self.layoutChanged.emit()
    
    def get_headers(self):
        """获取表头"""
        return self._headers
    
    def get_data(self):
        """获取所有数据"""
        return self._data
    
    def get_filtered_row_count(self):
        """获取过滤后的行数"""
        if self._use_filter and self._filtered_indices:
            return len(self._filtered_indices)
        return len(self._data)
    
    def reset_render_stats(self):
        """重置渲染统计"""
        self._render_count = 0
        self._rendered_rows.clear()
    
    def get_render_stats(self):
        """获取渲染统计"""
        return {
            'total_rows': len(self._data),
            'unique_rows_rendered': len(self._rendered_rows),
            'total_data_calls': self._render_count
        }

    def append_rows(self, new_rows):
        """追加新行数据"""
        if not new_rows:
            return 0
        
        start_row = len(self._data)
        end_row = start_row + len(new_rows) - 1
        
        self.beginInsertRows(QModelIndex(), start_row, end_row)
        self._data.extend(new_rows)
        self.endInsertRows()  # 修复：添加括号
        
        return len(new_rows)


class RBookTableView(QMainWindow):
    """图书库管理表格视图主窗口"""
    
    def __init__(self):
        super().__init__()
        self.model = RBookTableModel()
        self.stats_dock = None
        self.stats_timer = None
        self.csv_file_path = None
        self.load_rows = 10000
        self.is_loading = False
        # 从data.py导入选项列表
        self.categories = [
            '文学', '历史', '哲学', '艺术', '社会科学', '自然科学',
            '工业技术', '计算机', '经济', '管理', '教育', '语言',
            '小说', '诗歌', '散文', '传记'
        ]
        
        self.authors = [
            '鲁迅', '老舍', '巴金', '茅盾', '钱钟书', '沈从文', '张爱玲', '冰心',
            '曹雪芹', '吴承恩', '施耐庵', '罗贯中', '金庸', '古龙', '梁羽生',
            '莫言', '余华', '王小波', '刘慈欣', '韩寒', '郭敬明', '安妮宝贝'
        ]
        
        self.publishers = [
            '人民文学出版社', '作家出版社', '中华书局', '商务印书馆', '三联书店',
            '上海译文出版社', '北京大学出版社', '清华大学出版社', '机械工业出版社',
            '电子工业出版社', '科学出版社', '高等教育出版社'
        ]
        
        self.statuses = ['在架', '借出', '维修', '下架']
        
        self.notes_options = ['', '热门', '新书', '推荐', '畅销', '经典', '珍藏版']
        
        # 创建代理
        self.category_delegate = RBookComboBoxDelegate(self.categories)
        self.author_delegate = RBookComboBoxDelegate(self.authors)
        self.publisher_delegate = RBookComboBoxDelegate(self.publishers)
        self.status_delegate = RBookComboBoxDelegate(self.statuses)
        self.notes_delegate = RBookComboBoxDelegate(self.notes_options)
        self.checkbox_delegate = RBookCheckBoxDelegate()
        self.lineedit_delegate = RBookLineEditDelegate()
        self.date_delegate = RBookDateDelegate()
        self.color_delegate = RBookColorDelegate()
        self.init_ui()
        
        # 自动加载data.csv
        import os
        csv_path = os.path.join(os.path.dirname(__file__), 'data.csv')
        if os.path.exists(csv_path):
            self.load_csv_file(csv_path, self.load_rows)  # 初始加载10000行
    
    def init_ui(self):
        """初始化UI"""
        self.setWindowTitle('图书库管理系统 - RBookTableView')
        self.setGeometry(100, 100, 1400, 800)
        
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        
        # 工具栏
        toolbar_layout = QHBoxLayout()
        
        self.load_btn = QPushButton('加载CSV文件')
        self.load_btn.clicked.connect(self.load_csv)
        toolbar_layout.addWidget(self.load_btn)
        
        self.save_btn = QPushButton('保存CSV文件')
        self.save_btn.clicked.connect(self.save_csv)
        toolbar_layout.addWidget(self.save_btn)
        
        self.row_count_label = QLabel('行数: 0')
        toolbar_layout.addWidget(self.row_count_label)
        
        toolbar_layout.addStretch()
        layout.addLayout(toolbar_layout)
        
        # 表格视图
        self.table_view = QTableView()
        self.table_view.setModel(self.model)
        self.table_view.setAlternatingRowColors(True)
        self.table_view.setSortingEnabled(False)
        
        # 性能优化设置
        #self.table_view.setVerticalScrollMode(QTableView.ScrollMode.ScrollPerPixel)
        #self.table_view.setHorizontalScrollMode(QTableView.ScrollMode.ScrollPerPixel)
        self.table_view.setVerticalScrollMode(QTableView.ScrollMode.ScrollPerItem)
        self.table_view.setHorizontalScrollMode(QTableView.ScrollMode.ScrollPerItem)
        self.table_view.verticalHeader().setDefaultSectionSize(24)
        self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Fixed)
        
        # 表头自适应
        header = self.table_view.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
        header.setStretchLastSection(True)
        
        layout.addWidget(self.table_view)
        
        # 创建统计DockWidget
        self.create_stats_dock()
        
        # 启动定时器
        self.start_stats_timer()
        
        # 状态栏
        self.statusBar().showMessage('就绪')
    
    def on_scrollbar_valueChanged(self, value:int)->None:
        scrollbar: QScrollBar = self.table_view.verticalScrollBar()
        total: int = scrollbar.maximum()
        if total > 0 and value >= total*0.8:
            current_rows = self.model.rowCount()
            if( not self.is_loading and self.csv_file_path and current_rows < self.model._total_count):
                self.auto_load_more_data()

    def auto_load_more_data(self):
        """自动加载更多数据"""
        self.is_loading = True
        current_rows: int = self.model.rowCount()
        remaining: int = self.model._total_count-2-current_rows
        batch_size = min(self.load_rows,remaining)
        batch_start_time = time.time()
        if batch_size > 0:
            self.statusBar().showMessage(f'正在加载更多数据... ({current_rows} -> {current_rows + batch_size})')
            QApplication.processEvents() 

        try:
            import csv
            with open(self.csv_file_path,'r',encoding='utf-8') as f:
                reader = csv.reader(f)
                totals = next(reader)
                headers=next(reader)
                for _ in range(current_rows):
                    next(reader)

                new_rows = []
                for i,row in enumerate(reader):
                    if i>=batch_size:
                        break
                    new_rows.append(row)
                if new_rows:
                    added_count = self.model.append_rows(new_rows)
                    batch_elapsed = time.time() - batch_start_time
                    
                    # 更新显示
                    total = int(totals[0]) - 2
                    loaded_rows = self.model.rowCount()
                    
                    if loaded_rows < total:
                        self.row_count_label.setText(f'行数: {loaded_rows} / {total} (滚动自动加载)')
                        status_msg = f'已加载 {loaded_rows} / {total} 行 | 此批耗时: {batch_elapsed:.3f}秒'
                        self.statusBar().showMessage(status_msg)
                        print(f"[Performance] 懒加载批次 | 加载 {added_count} 行 | 耗时: {batch_elapsed:.3f}秒")
                    else:
                        self.row_count_label.setText(f'行数: {loaded_rows} (全部加载完成)')
                        self.statusBar().showMessage('所有数据已加载完成！')
                        print(f"[Performance] 懒加载完成 | 总行数: {loaded_rows}")
        except Exception as e:
            error_msg = f'加载更多数据失败: {str(e)}'
            self.statusBar().showMessage(error_msg)
            print(error_msg)
        
        finally:
            self.is_loading = False
    
    def load_csv(self):
        """打开文件对话框加载CSV"""
        filepath, _ = QFileDialog.getOpenFileName(
            self, '选择CSV文件', '', 'CSV文件 (*.csv);;所有文件 (*.*)'
        )
        if filepath:
            self.load_csv_file(filepath)
    
    def load_csv_file(self, filepath, load_rows=None):
        """加载CSV文件"""
        success, message = self.model.load_csv(filepath, load_rows)
        
        if success:
            headers = self.model.get_headers()
            self.csv_file_path = filepath
            # 设置各列的代理
            if 'category' in headers:
                col = headers.index('category')
                self.table_view.setItemDelegateForColumn(col, self.category_delegate)
            
            if 'author' in headers:
                col = headers.index('author')
                self.table_view.setItemDelegateForColumn(col, self.author_delegate)
            
            if 'publisher' in headers:
                col = headers.index('publisher')
                self.table_view.setItemDelegateForColumn(col, self.publisher_delegate)
            
            if 'title' in headers:
                col = headers.index('title')
                self.table_view.setItemDelegateForColumn(col, self.lineedit_delegate)
            
            if 'notes' in headers:
                col = headers.index('notes')
                self.table_view.setItemDelegateForColumn(col, self.notes_delegate)
            
            if 'borrowed' in headers:
                col = headers.index('borrowed')
                self.table_view.setItemDelegateForColumn(col, self.checkbox_delegate)
            
            if 'publish_date' in headers:
                col = headers.index('publish_date')
                self.table_view.setItemDelegateForColumn(col, self.date_delegate)
            if 'color' in headers:
                col = headers.index('color')
                self.table_view.setItemDelegateForColumn(col,self.color_delegate)
            
            # 更新行数显示
            loaded_rows = self.model.rowCount()
            total_rows = self.model._total_count - 2
            self.row_count_label.setText(f'行数: {loaded_rows} / {total_rows}')
            self.statusBar().showMessage(message)
            
            # 连接滚动条事件（用于懒加载）
            scrollbar = self.table_view.verticalScrollBar()
            scrollbar.valueChanged.connect(self.on_scrollbar_valueChanged)
            
            # 自适应列宽
            self.table_view.resizeColumnsToContents()
        else:
            self.statusBar().showMessage(message)
            QMessageBox.warning(self, '加载错误', message)
    
    def save_csv(self):
        """保存CSV文件"""
        filepath, _ = QFileDialog.getSaveFileName(
            self, '保存CSV文件', '', 'CSV文件 (*.csv);;所有文件 (*.*)'
        )
        if filepath:
            try:
                with open(filepath, 'w', encoding='utf-8', newline='') as f:
                    writer = csv.writer(f)
                    # 写入总行数
                    total = len(self.model.get_data()) + 2
                    writer.writerow([total])
                    # 写入表头
                    writer.writerow(self.model.get_headers())
                    # 写入数据
                    writer.writerows(self.model.get_data())
                
                self.statusBar().showMessage(f'成功保存到: {filepath}')
                QMessageBox.information(self, '保存成功', f'数据已保存到:\n{filepath}')
            except Exception as e:
                error_msg = f'保存失败: {str(e)}'
                self.statusBar().showMessage(error_msg)
                QMessageBox.critical(self, '保存错误', error_msg)
    
    def create_stats_dock(self):
        """创建渲染统计DockWidget"""
        self.stats_dock = QDockWidget('渲染统计 (虚拟化验证)', self)
        self.stats_dock.setAllowedAreas(Qt.DockWidgetArea.LeftDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea)
        
        stats_widget = QWidget()
        stats_layout = QVBoxLayout(stats_widget)
        
        title_label = QLabel('实时渲染统计')
        title_label.setStyleSheet('font-weight: bold; font-size: 14px; padding: 5px;')
        stats_layout.addWidget(title_label)
        
        self.stats_text = QTextEdit()
        self.stats_text.setReadOnly(True)
        self.stats_text.setStyleSheet("""
            QTextEdit {
                background-color: #2b2b2b;
                color: #00ff00;
                font-family: 'Consolas', 'Monaco', monospace;
                font-size: 11px;
                border: 1px solid #555;
                padding: 5px;
            }
        """)
        stats_layout.addWidget(self.stats_text, 1)
        
        btn_layout = QHBoxLayout()
        
        reset_btn = QPushButton('重置统计')
        reset_btn.clicked.connect(self.reset_stats)
        btn_layout.addWidget(reset_btn)
        
        refresh_btn = QPushButton('立即刷新')
        refresh_btn.clicked.connect(self.update_stats_display)
        btn_layout.addWidget(refresh_btn)
        
        stats_layout.addLayout(btn_layout, 0)
        
        self.stats_dock.setWidget(stats_widget)
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.stats_dock)
    
    def start_stats_timer(self):
        """启动定时器"""
        self.stats_timer = QTimer(self)
        self.stats_timer.timeout.connect(self.update_stats_display)
        self.stats_timer.start(1000)
    
    def update_stats_display(self):
        """更新统计显示"""
        stats = self.model.get_render_stats()
        total = stats['total_rows']
        rendered = stats['unique_rows_rendered']
        calls = stats['total_data_calls']
        
        virtualization_rate = 0
        if total > 0:
            virtualization_rate = ((total - rendered) / total) * 100
        
        stats_text = f"""
总数据行数:     {total:,}
已渲染行数:     {rendered:,}
data()调用次数: {calls:,}
• 单击可编辑列即可修改
"""
        
        self.stats_text.setPlainText(stats_text)
    
    def reset_stats(self):
        """重置统计"""
        self.model.reset_render_stats()
        self.update_stats_display()
        self.statusBar().showMessage('统计已重置', 2000)


class RBookTreeView(QMainWindow):
    """图书树形视图 - 支持分类→作者→书名三级折叠"""
    
    def __init__(self):
        super().__init__()
        self.is_loading = False
        self.setWindowTitle('图书库管理系统 - 树形视图')
        self.setGeometry(100, 100, 1400, 800)
        self.csv_file_path : str = ''
        # 下拉选项
        self.categories = ['文学', '历史', '哲学', '艺术', '计算机', '经济', '科学', '教育', '社会', '医学', '法律', '心理', '传记', '小说', '诗歌', '其他']
        self.authors = ['鲁迅', '老舍', '巴金', '茅盾', '沈从文', '钱锺书', '史铁生', '林语堂', '沈石溪', '张爱玲', '梁启超', '胡适', '费孝通', '季羡林', '赵树理', '严复', '黄仁宇', '楊绠', '柳青', '张恒', '李明', '高建群']
        self.publishers = ['人民文学出版社', '三联书店', '中华书局', '商务印书馆', '机械工业出版社', '北京大学出版社', '清华大学出版社', '中国科学技术出版社', '中国社会科学出版社', '上海译文出版社', '广西师范大学出版社', '电子工业出版社']
        self.statuses = ['在架', '借出', '维修', '下架']
        self.notes_options = ['无', '新书', '热门', '经典', '珍本', '限量', '即将到货']
        
        # 创建模型
        self.tree_model = RBookTreeModel()
        
        # 创建代理
        self.category_delegate = RBookComboBoxDelegate(self.categories)
        self.author_delegate = RBookComboBoxDelegate(self.authors)
        self.publisher_delegate = RBookComboBoxDelegate(self.publishers)
        self.status_delegate = RBookComboBoxDelegate(self.statuses)
        self.notes_delegate = RBookComboBoxDelegate(self.notes_options)
        self.checkbox_delegate = RBookCheckBoxDelegate()  # CheckBox代理
        self.lineedit_delegate = RBookLineEditDelegate()
        self.date_delegate = RBookDateDelegate()
        self.color_delegate = RBookColorDelegate()
        
        self.init_ui()
        
        # 自动加载数据
        import os
        csv_path = os.path.join(os.path.dirname(__file__), 'data.csv')
        import os
        if os.path.exists(csv_path):
            self.load_csv_file(csv_path, max_rows=1000)
    
    def init_ui(self):
        """初始化UI"""
        # 中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        
        # 工具栏
        toolbar_layout = QHBoxLayout()
        
        load_btn = QPushButton('加载CSV文件')
        load_btn.clicked.connect(self.load_csv_dialog)
        toolbar_layout.addWidget(load_btn)
        
        expand_all_btn = QPushButton('展开所有')
        expand_all_btn.clicked.connect(self.expand_all)
        toolbar_layout.addWidget(expand_all_btn)
        
        collapse_all_btn = QPushButton('折叠所有')
        collapse_all_btn.clicked.connect(self.collapse_all)
        toolbar_layout.addWidget(collapse_all_btn)
        
        expand_level1_btn = QPushButton('展开至分类')
        expand_level1_btn.clicked.connect(lambda: self.tree_view.expandToDepth(0))
        toolbar_layout.addWidget(expand_level1_btn)
        
        expand_level2_btn = QPushButton('展开至作者')
        expand_level2_btn.clicked.connect(lambda: self.tree_view.expandToDepth(1))
        toolbar_layout.addWidget(expand_level2_btn)
        
        toolbar_layout.addStretch()
        
        # 添加"加载更多"按钮
        self.load_more_btn = QPushButton('加载更多数据')
        self.load_more_btn.clicked.connect(self.load_more_data)
        self.load_more_btn.setEnabled(False)  # 初始禁用
        toolbar_layout.addWidget(self.load_more_btn)
        
        self.row_count_label = QLabel('行数: 0')
        toolbar_layout.addWidget(self.row_count_label)
        
        layout.addLayout(toolbar_layout)
        
        # 树形视图
        self.tree_view = QTreeView()
        self.tree_view.setModel(self.tree_model)
        self.tree_view.setAlternatingRowColors(True)
        self.tree_view.setSortingEnabled(False)
        self.tree_view.setEditTriggers(QTreeView.EditTrigger.SelectedClicked)
        
        # 表头设置
        header = self.tree_view.header()
        header.setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
        header.setStretchLastSection(True)

        #监听滚动事件
        scrollbar: QScrollBar = self.tree_view.verticalScrollBar()
        scrollbar.valueChanged.connect(self.on_scrollbar_valueChanged)
        
        layout.addWidget(self.tree_view)
        
        # 状态栏
        self.statusBar().showMessage('就绪')
    
    def on_scrollbar_valueChanged(self, value:int)->None:
        """滚动条变化时检查是否需要自动加载更多数据"""
        scrollbar: QScrollBar = self.tree_view.verticalScrollBar()
        total: int = scrollbar.maximum()
        
        # 滚动到底部80%时自动加载
        if total > 0 and value >= total * 0.8:
            progress = self.tree_model.get_load_progress()
            if not self.is_loading and progress['remaining'] > 0:
                self.auto_load_more_data()

    def auto_load_more_data(self):
        """自动加载更多数据（懒加载）"""
        if self.is_loading:
            return
        
        self.is_loading = True
        progress = self.tree_model.get_load_progress()
        
        if progress['remaining'] > 0:
            self.statusBar().showMessage(f'正在加载更多数据... ({progress["loaded"]} -> {progress["loaded"] + 1000})')
            QApplication.processEvents()
            
            count, message = self.tree_model.append_more_data(self.csv_file_path, batch_size=1000)
            
            if count > 0:
                # 更新显示
                progress = self.tree_model.get_load_progress()
                self.row_count_label.setText(f'图书数: {progress["loaded"]} / {progress["total"]}')
                self.statusBar().showMessage(message)
                
                # 更新"加载更多"按钮状态
                if progress['remaining'] > 0:
                    self.load_more_btn.setEnabled(True)
                    self.load_more_btn.setText(f'加载更多 (剩余 {progress["remaining"]} 行)')
                else:
                    self.load_more_btn.setEnabled(False)
                    self.load_more_btn.setText('全部已加载')
            else:
                self.statusBar().showMessage(message)
        
        self.is_loading = False
    
    def load_more_data(self):
        """手动点击按钮加载更多数据"""
        self.auto_load_more_data()

    def load_csv_dialog(self):
        """打开文件对话框"""
        filepath, _ = QFileDialog.getOpenFileName(
            self, '选择CSV文件', '', 'CSV Files (*.csv);;All Files (*)'
        )
        if filepath:
            self.load_csv_file(filepath)
    
    def load_csv_file(self, filepath, max_rows=None):
        """加载CSV文件"""
        self.statusBar().showMessage(f'正在加载: {filepath}...')
        QApplication.processEvents()
        
        success, message = self.tree_model.load_csv_to_tree(filepath, max_rows)
        
        if success:
            # 设置代理
            headers = self.tree_model.get_headers()
            self.csv_file_path = filepath
            
            # 更新进度显示
            progress = self.tree_model.get_load_progress()
            self.row_count_label.setText(f'图书数: {progress["loaded"]} / {progress["total"]}')
            
            # 更新"加载更多"按钮
            if progress['remaining'] > 0:
                self.load_more_btn.setEnabled(True)
                self.load_more_btn.setText(f'加载更多 (剩余 {progress["remaining"]} 行)')
            else:
                self.load_more_btn.setEnabled(False)
                self.load_more_btn.setText('全部已加载')
            
            if 'category' in headers:
                col = headers.index('category')
                #self.tree_view.setItemDelegateForColumn(col, self.category_delegate)
            if 'author' in headers:
                col = headers.index('author')
                #self.tree_view.setItemDelegateForColumn(col, self.author_delegate)
            if 'publisher' in headers:
                col = headers.index('publisher')
                #self.tree_view.setItemDelegateForColumn(col, self.publisher_delegate)
            if 'status' in headers:
                col = headers.index('status')
                self.tree_view.setItemDelegateForColumn(col, self.status_delegate)
            if 'notes' in headers:
                col = headers.index('notes')
                self.tree_view.setItemDelegateForColumn(col, self.notes_delegate)

            if 'borrowed' in headers:
                col = headers.index('borrowed')
                self.tree_view.setItemDelegateForColumn(col, self.checkbox_delegate)
            if 'title' in headers:
                col = headers.index('title')
                self.tree_view.setItemDelegateForColumn(col, self.lineedit_delegate)
            if 'publish_date' in headers:
                col = headers.index('publish_date')
                self.tree_view.setItemDelegateForColumn(col, self.date_delegate)
            if 'color' in headers:
                col = headers.index('color')
                self.tree_view.setItemDelegateForColumn(col, self.color_delegate)

            
            # 默认展开至分类级别
            self.tree_view.expandToDepth(0)
            
            self.statusBar().showMessage(message)
        else:
            self.statusBar().showMessage(message)
            QMessageBox.critical(self, '加载错误', message)
    
    def expand_all(self):
        """展开所有节点"""
        self.tree_view.expandAll()
        self.statusBar().showMessage('已展开所有节点', 2000)
    
    def collapse_all(self):
        """折叠所有节点"""
        self.tree_view.collapseAll()
        self.statusBar().showMessage('已折叠所有节点', 2000)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    
    # 选择视图类型
    choice = QMessageBox.question(
        None,
        '选择视图类型',
        '请选择要使用的视图：\n\n'
        '• Yes - 树形视图（分类→作者→书名 折叠）\n'
        '• No - 表格视图（传统平面表格）',
        QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
        QMessageBox.StandardButton.Yes
    )
    
    if choice == QMessageBox.StandardButton.Yes:
        window = RBookTreeView()  # 树形视图
    else:
        window = RBookTableView()  # 表格视图
    
    window.show()
    sys.exit(app.exec())  # PySide6使用exec()而不exec_()
